package com.linkoog.devtools.utils;

import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiAnnotationMemberValue;
import com.intellij.psi.PsiArrayInitializerMemberValue;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiLiteral;
import com.intellij.psi.PsiLiteralExpression;
import com.intellij.psi.PsiNameValuePair;
import com.intellij.psi.PsiPolyadicExpression;
import com.intellij.psi.PsiReferenceExpression;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

public class PsiElementUtil {



    /**
     *  根据文件获取Module
     */
    public static Module findModule(@NotNull final PsiElement psiElement) {
        return ModuleUtilCore.findModuleForPsiElement(psiElement);
    }


    public static String resolveModuleFilePath(@NotNull PsiElement psiElement){
        Module module = ModuleUtil.findModuleForPsiElement(psiElement);
        if (module != null){
            return module.getModuleFilePath();
        }
        return null;
    }


    /**
     *  解析 PsiAnnotation 的属性值
     */
    public static List<String> parsePsiAnnotationAttributeValue(PsiAnnotation psiAnnotation, String... attributeName){
        return parsePsiAnnotationAttributeValue(psiAnnotation,true, attributeName);
    }

    /**
     *  解析 PsiAnnotation 的属性值
     */
    public static List<String> parsePsiAnnotationAttributeValue(PsiAnnotation psiAnnotation, boolean isDeclaredAttribute, String... attributeName){
        if (psiAnnotation == null || attributeName == null || attributeName.length == 0){
            return null;
        }

        List<String> result = new ArrayList<>();
        PsiAnnotationMemberValue psiAnnotationMemberValue = null;
        if (isDeclaredAttribute){
            for (String name : attributeName) {
                psiAnnotationMemberValue = psiAnnotation.findDeclaredAttributeValue(name);
                if (psiAnnotationMemberValue != null){
                    break;
                }
            }
        }else {
            for (String name : attributeName) {
                psiAnnotationMemberValue = psiAnnotation.findAttributeValue(name);
                if (psiAnnotationMemberValue != null){
                    break;
                }
            }
        }

        if (psiAnnotationMemberValue == null){
            return result;
        }

        if (psiAnnotationMemberValue instanceof PsiLiteralExpression) {
            final Object value = ((PsiLiteral)psiAnnotationMemberValue).getValue();
            if (value instanceof String) result.add((String)value);
        }else if (psiAnnotationMemberValue instanceof PsiReferenceExpression) {
            PsiReferenceExpression expression = (PsiReferenceExpression) psiAnnotationMemberValue;
            PsiElement psiElement = expression.resolve();

            if(psiElement instanceof PsiField) {
                String fieldValue = ((PsiField) psiElement).computeConstantValue().toString();
                if (fieldValue.startsWith("PsiField:")) {
                    result.add(fieldValue.substring(9));
                } else {
                    result.add(fieldValue);
                }
            }
        }else if (psiAnnotationMemberValue instanceof PsiArrayInitializerMemberValue) {
            PsiArrayInitializerMemberValue arrayValue = (PsiArrayInitializerMemberValue) psiAnnotationMemberValue;

            for (PsiAnnotationMemberValue initializer : arrayValue.getInitializers()) {
                if (initializer instanceof PsiPolyadicExpression) {
                    result.add(parsePsiPolyadicExpression((PsiPolyadicExpression) initializer));
                } else if (initializer instanceof PsiReferenceExpression) {
                    PsiReferenceExpression expression = (PsiReferenceExpression) initializer;
                    PsiElement psiElement = expression.resolve();

                    if(psiElement instanceof PsiField) {
                        result.add(((PsiField) psiElement).computeConstantValue().toString());
                    } else {
                        result.add(expression.getText());
                    }
                } else {
                    result.add(initializer.getText().replaceAll("\\\"", ""));
                }
            }
        } else if (psiAnnotationMemberValue instanceof PsiPolyadicExpression) {
            result.add(parsePsiPolyadicExpression((PsiPolyadicExpression) psiAnnotationMemberValue));
        } else {
            result.add(psiAnnotationMemberValue.getText());
        }

        return result;
    }

    private static String parsePsiPolyadicExpression(PsiPolyadicExpression polyadicExpression) {
        PsiExpression[] operands = polyadicExpression.getOperands();

        StringBuilder fullTextBuilder = new StringBuilder("");

        for (PsiExpression operand : operands) {
            if (operand instanceof PsiReferenceExpression) {
                PsiElement element = ((PsiReferenceExpression) operand).resolve();
                if (element instanceof PsiField) {
                    fullTextBuilder.append(((PsiField) element).computeConstantValue().toString());
                }
            } else if (operand instanceof PsiLiteralExpression) {
                fullTextBuilder.append(((PsiLiteralExpression) operand).getValue());
            }
        }

        return fullTextBuilder.toString();
    }

    private static List<String> getValues(PsiNameValuePair psiNameValuePair) {
        List<String> values = new ArrayList<>();
        PsiAnnotationMemberValue value = psiNameValuePair.getValue();

        if (value instanceof PsiReferenceExpression) {
            PsiReferenceExpression expression = (PsiReferenceExpression) value;
            PsiElement psiElement = expression.resolve();

            if(psiElement instanceof PsiField) {
                String fieldValue = ((PsiField) psiElement).computeConstantValue().toString();
                if (fieldValue.startsWith("PsiField:")) {
                    values.add(fieldValue.substring(9));
                } else {
                    values.add(fieldValue);
                }
            }
        } else if (value instanceof PsiLiteralExpression) {
            values.add(psiNameValuePair.getLiteralValue());
        } else if (value instanceof PsiArrayInitializerMemberValue) {
            PsiArrayInitializerMemberValue arrayValue = (PsiArrayInitializerMemberValue) value;

            for (PsiAnnotationMemberValue initializer : arrayValue.getInitializers()) {
                if (initializer instanceof PsiPolyadicExpression) {
                    values.add(getFullUrlFromExpression((PsiPolyadicExpression) initializer));
                } else if (initializer instanceof PsiReferenceExpression) {
                    PsiReferenceExpression expression = (PsiReferenceExpression) initializer;
                    PsiElement psiElement = expression.resolve();

                    if(psiElement instanceof PsiField) {
                        values.add(((PsiField) psiElement).computeConstantValue().toString());
                    } else {
                        values.add(expression.getText());
                    }
                } else {
                    values.add(initializer.getText().replaceAll("\\\"", ""));
                }
            }
        } else if (value instanceof PsiPolyadicExpression) {
            values.add(getFullUrlFromExpression((PsiPolyadicExpression) value));
        } else {
            values.add(value.getText());
        }
        return values;
    }

    private static String getFullUrlFromExpression(PsiPolyadicExpression polyadicExpression) {
        PsiExpression[] operands = polyadicExpression.getOperands();

        StringBuilder fullUrl = new StringBuilder("");

        for (PsiExpression operand : operands) {
            if (operand instanceof PsiReferenceExpression) {
                PsiElement element = ((PsiReferenceExpression) operand).resolve();
                if (element instanceof PsiField) {
                    fullUrl.append(((PsiField) element).computeConstantValue().toString());
                }
            } else if (operand instanceof PsiLiteralExpression) {
                fullUrl.append(((PsiLiteralExpression) operand).getValue());
            }
        }

        return fullUrl.toString();
    }

    private static List<String> getAttributeValue(PsiNameValuePair[] attributes, String attributeName) {
        List<String> values = new ArrayList<>();

        if (attributes != null && attributes.length == 1) {
            PsiNameValuePair psiNameValuePair = attributes[0];

            if (psiNameValuePair.getName() != null && psiNameValuePair.getName().equalsIgnoreCase(attributeName) ||
                    psiNameValuePair.getName() == null &&
                            ("value".equalsIgnoreCase(attributeName) || "path".equalsIgnoreCase(attributeName))) {
                return getValues(psiNameValuePair);
            }
        } else if (attributes != null && attributes.length > 1) {
            Optional<PsiNameValuePair> psiNameValuePair =
                    Stream.of(attributes)
                            .filter(a -> a.getName() != null && a.getName().equalsIgnoreCase(attributeName))
                            .findFirst();

            if (psiNameValuePair.isPresent()) {
                return getValues(psiNameValuePair.get());
            }
        }

        return values;
    }






}